﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using COFE.Core.Actions;
using COFE.Core;

namespace COFE.Data
{
    /// <summary>
    /// Find expired entry and update them.
    /// </summary>
    public class FindExpiredEntryWork : WorkBase
    {
        private int maxHandleCount = 1000;

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="workId"></param>
        /// <param name="handlePropertyCount">How many entries with property expired are scheduled to cache.</param>
        /// <param name="handleEntryCount">How many entries expired are scheduled to cache.</param>
        /// <param name="handleExpiredCount">How many entries with listing expired are scheduled to cache.</param>
        public FindExpiredEntryWork(Guid workId,
            int handlePropertyCount = -1, int handleEntryCount = -1,
            int handleListCount = -1)
            : base(workId, "COFEDB", "FindExpiredEntryWork", ""/* No Parameter */) 
        {            
            Description = "Find_Expired_Entry";
            _handlePropertyCount = handlePropertyCount == -1 ? maxHandleCount : handlePropertyCount;
            _handleEntryCount = handleEntryCount == -1 ? maxHandleCount : handleEntryCount;
            _handleListCount = handleListCount == -1 ? maxHandleCount : handleListCount;
        }

        public static Guid ScheduleWork(
            int handlePropertyCount = -1, int handleEntryCount = -1,
            int handleListCount = -1)
        {
            var work = new FindExpiredEntryWork(Guid.NewGuid(),
                handlePropertyCount, handleEntryCount, handleListCount);
            return COFEActionShared.WorkScheduler.Enqueue(
                WorkPriority.Low, work);
        }


        #region Methods
        protected override void DoWork()
        {
            //Something is caching, skip.
            if (COFEActionShared.WorkScheduler.GetAllSchedules(
                (s) => (s.Work is CacheListingWork ||
                    s.Work is CacheListingWork || 
                    s.Work is CachePropertiesWork)).Any())
                return;

            Dictionary<Guid, string> propertyExpired = new Dictionary<Guid, string>();
            Dictionary<Guid, string> entryExpired = new Dictionary<Guid, string>();
            Dictionary<Guid, string> listExpired = new Dictionary<Guid, string>();
            Dictionary<Guid, string> list2Expired = new Dictionary<Guid, string>();

            COFEDBShared.DBOperations.ReadDatabase((context) =>
                {
                    DateTime propertyExpireTime = DateTime.UtcNow - COFEDBShared.TTLPropertyValues;
                    DateTime entryExpireTime = DateTime.UtcNow - COFEDBShared.TTLEntryExist;
                    DateTime listExpireTime = DateTime.UtcNow - COFEDBShared.TTLEntryList;


                    entryExpired = context.Entries.Where(
                        e => e.RefreshTime < entryExpireTime)
                        .OrderBy(e => e.RefreshTime)
                        //.Select(e => e.EntryId)
                        .Take(_handleEntryCount)
                        .ToDictionary(e => e.EntryId, e => COFEPath.FormatFullParseName(e.PrimaryVolumeId, e.ParsePath));

                    propertyExpired = context.Entries.Where(
                        e => e.PropertyRefreshTime < propertyExpireTime)
                        .OrderBy(e => e.PropertyRefreshTime)
                        .Take(_handlePropertyCount)
                        .ToDictionary(e => e.EntryId,
                        e => COFEPath.FormatFullParseName(e.PrimaryVolumeId, e.ParsePath));

                    listExpired = context.Entries.Where(
                        e => e is FolderEntry &&
                            (e as FolderEntry).LastListTime < listExpireTime &&
                            (e as FolderEntry).LastListTime <= COFEDBShared.DTMin
                            )                        
                        .OrderBy(e => (e as FolderEntry).LastListTime)
                        .Take(_handleListCount)
                        .ToDictionary(e => e.EntryId, e => COFEPath.FormatFullParseName(e.PrimaryVolumeId, e.ParsePath));


                    list2Expired = context.Entries.Where(
                        e => e is FileEntry &&
                            (e as FileEntry).IsFileBasedFS &&                            
                            ((e.EntryProperties.FirstOrDefault((ep) => 
                                ep.PropertyId == (int)DatabaseProperties.LastListTime))
                                as EntryProperty_DateTime).Value <= COFEDBShared.DTMin)
                        .Take(_handleListCount)
                        .ToDictionary(e => e.EntryId, e => COFEPath.FormatFullParseName(e.PrimaryVolumeId, e.ParsePath));

                    listExpired = listExpired.Union(list2Expired)
                        .OrderBy(e => e.Value.Length)
                        .Take(_handleListCount)
                        
                        .ToDictionary(e => e.Key, e => e.Value);

                    propertyExpired = propertyExpired.Where
                        (e => !entryExpired.ContainsKey(e.Key))                        
                        .ToDictionary(e => e.Key, e => e.Value);

                    if (entryExpired.ContainsKey(Guid.Empty))
                        entryExpired.Remove(Guid.Empty);
                });

            

            foreach (var e in propertyExpired)
                CachePropertiesWork.ScheduleWork(e.Key, e.Value);

            foreach (var e in entryExpired)
                CacheEntryWork.ScheduleWork(e.Key, e.Value);

            foreach (var e in listExpired)
            {
                CacheListingWork.ScheduleWork(e.Key, e.Value);
                //Console.WriteLine("CacheListing" +  e.Value);
            }
        }

        #endregion

        #region Data
        int _handlePropertyCount = -1;
        int _handleEntryCount = -1;
        int _handleListCount = -1;
        #endregion

    }
}
